// main.cpp 
#include <Arduino.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include <Ticker.h>
#include "Config.h"
#include "OLEDDisplay.h"
#include "DHT11Sensor.h"
#include "Buzzer.h"
#include "MotionSensor.h"
#include "LightSensor.h"
#include <ArduinoJson.h>
#include "MQ2Sensor.h"
#include "FlameSensor.h"
// 解决MQTT_KEEPALIVE重定义问题
#ifdef MQTT_KEEPALIVE
#undef MQTT_KEEPALIVE
#endif
#define MQTT_KEEPALIVE 60



// 函数前置声明
void WiFi_Connect();
bool OneNet_Connect();
void checkConnection();
void OneNet_Prop_Post();
void mqttCallback(char* topic, byte* payload, unsigned int length);
void reportStatus();
void reconnect();



// 设备配置
struct SensorConfig {
    const char* product_id;
    const char* device_id;
    const char* token;
};

const SensorConfig dht11Config = {
    "ZwQ1ozNTiF",
    "DHT11",
    "version=2018-10-31&res=products%2FZwQ1ozNTiF%2Fdevices%2FDHT11&et=1903525893&method=md5&sign=haLdBAU1q3iOG23ijwqwdw%3D%3D"
};

const SensorConfig humanConfig = {
    "ZwQ1ozNTiF",
    "Human",
    "version=2018-10-31&res=products%2FZwQ1ozNTiF%2Fdevices%2FHuman&et=1904056176000&method=md5&sign=Qf5YMx8vzBtMAUwcD9Aw3A%3D%3D"
};

const SensorConfig fanConfig = {
    "ZwQ1ozNTiF",
    "feng_control",
    "version=2018-10-31&res=products%2FZwQ1ozNTiF%2Fdevices%2Ffeng_control&et=1872596263000&method=md5&sign=HFmI0xZxOw4usRXW%2B4i%2FBA%3D%3D"
};

const SensorConfig lightConfig = {
    "ZwQ1ozNTiF",
    "Light",
    "version=2018-10-31&res=products%2FZwQ1ozNTiF%2Fdevices%2FLight&et=1872596263000&method=md5&sign=HFmI0xZxOw4usRXW%2B4i%2FBA%3D%3D"
};

// 全局变量
int postMsgID = 0;
bool humanDetected = false;
bool fanState = false;
unsigned long lastReconnectAttempt = 0;

// 设备初始化
DHT11Sensor dht11(DHTPIN);
EnvMonitorDisplay oled;
Buzzer alarmBuzzer(BUZZER_PIN, true);
MQ2Sensor mq2(MQ2_AO_PIN, MQ2_DO_PIN);
static FlameSensor flame(FLAME_SENSOR_PIN);

MotionSensor motion(MOTION_PIN);
LightSensor light(LIGHT_SENSOR_PIN);
static WiFiClient espClient;
static PubSubClient client(espClient);
Ticker ticker;



void setup() {

     // 串口初始化
     Serial.begin(9600);
    while(!Serial); // 等待串口连接

    // 初始化引脚
    pinMode(LED, OUTPUT);
    pinMode(LED_PIN, OUTPUT);
    pinMode(FAN_PIN, OUTPUT);
    digitalWrite(FAN_PIN, LOW);
    pinMode(BUZZER_PIN, OUTPUT);
    digitalWrite(BUZZER_PIN, HIGH);
    
   
    while(!Serial); // 等待串口就绪
    Serial.setDebugOutput(true); // 启用调试输出
    Serial.println("\n串口初始化完成");
    
    // 传感器初始化
    if(!oled.begin()) {
        Serial.println("OLED初始化失败!");
        while(1);
    }
    dht11.begin();
    alarmBuzzer.begin();
    motion.begin();
    light.begin();
    mq2.begin(); 
    flame.begin();


    // 显示启动画面
    oled.showSplashScreen("环境监测系统", "启动中...");
    delay(2000);
    
    // 网络连接
    WiFi_Connect();
    OneNet_Connect();
    // 初始化MQTT
    client.setServer(mqtt_server, mqtt_port);
    client.setCallback(mqttCallback);
    
    if (client.connect(dht11Config.device_id, dht11Config.product_id, dht11Config.token)) {
        Serial.println("MQTT连接成功");
        
        String subTopic = String("$sys/") + dht11Config.product_id + "/" + dht11Config.device_id + "/thing/property/set";
        client.subscribe(subTopic.c_str());
    }
    
    // 定时任务
    ticker.attach(10, OneNet_Prop_Post);
    Serial.println("系统初始化完成");
}

void loop() {
    // 网络维护
    checkConnection();
    
    // 传感器处理
    static uint32_t lastUpdate = 0;
    if (millis() - lastUpdate > 2000) {
        // 读取传感器数据
        dht11.readData();
        humanDetected = motion.isHumanDetected();
        mq2.update();
         // 火焰检测
         bool flameDetected = flame.isFlameDetected();
        
         // 报警控制
         bool shouldAlarm = flameDetected || 
                          (mq2.isPreheated() && mq2.isAlert());
         
         digitalWrite(BUZZER_PIN, shouldAlarm ? LOW : HIGH);
         
         if(flameDetected) {
             Serial.println("[警报] 检测到火焰!");
         }


        // 控制外接LED
        light.controlLED(LED_PIN);
        
        // 温度控制
        float currentTemp = dht11.getTemperature();
        if (currentTemp > TEMP_THRESHOLD && !fanState) {
            fanState = true;
            digitalWrite(FAN_PIN, HIGH);
            alarmBuzzer.alert(2000);
            Serial.printf("[风扇] 温度超标(%.1f℃)，开启风扇\n", currentTemp);
        } else if (currentTemp <= TEMP_THRESHOLD && fanState) {
            fanState = false;
            digitalWrite(FAN_PIN, LOW);
            Serial.printf("[风扇] 温度正常(%.1f℃)，关闭风扇\n", currentTemp);
        }
        
        // OLED显示更新 (修正参数数量)
        oled.update(dht11.getTemperature(), 
                   dht11.getHumidity(),
                   mq2.getConcentration(),
                   WiFi.status() == WL_CONNECTED,
                   client.connected(),
                   postMsgID,
                   humanDetected,
                   light.getLightState(),
                   flameDetected); 
        Serial.printf("传感器数据: %.1f°C %d%% 人体检测: %s\n", 
                      dht11.getTemperature(), 
                      dht11.getHumidity(), 
                      humanDetected ? "有人" : "无人");
        
        lastUpdate = millis();
    }

client.loop();
// 每5秒上报一次状态
static unsigned long lastReport = 0;
if (millis() - lastReport > 5000) {
  reportStatus();
  lastReport = millis();
    }
}





void reconnect() {
    Serial.println("尝试重新连接MQTT...");
    if (client.connect(dht11Config.device_id, dht11Config.product_id, dht11Config.token)) {
        Serial.println("MQTT重新连接成功");
        String subTopic = String("$sys/") + dht11Config.product_id + "/" + dht11Config.device_id + "/thing/property/set";
        if (client.subscribe(subTopic.c_str())) {
            Serial.println("主题订阅成功");
        } else {
            Serial.println("主题订阅失败");
        }
    } else {
        Serial.printf("重新连接失败，状态码: %d\n", client.state());
    }
}



// 修改后的mqttCallback函数
void mqttCallback(char* topic, byte* payload, unsigned int length) {
    Serial.print("收到消息 [");
    Serial.print(topic);
    Serial.print("] ");
    
    String message;
    for (int i = 0; i < length; i++) {
        message += (char)payload[i];
    }
    Serial.println(message);

    if (strstr(topic, "property/set")) {
        JsonDocument doc;
        DeserializationError error = deserializeJson(doc, message);
        
        if (error) {
            Serial.print("JSON解析失败: ");
            Serial.println(error.c_str());
            return;
        }

        JsonObject params = doc["params"];
        if (!params.isNull()) {
            if (params["f_btn"].is<bool>()) {
                fanState = params["f_btn"];
                digitalWrite(FAN_PIN, fanState ? HIGH : LOW);
                Serial.printf("风扇已%s\n", fanState ? "开启" : "关闭");
            }
            if (params["lgt_p"].is<bool>()) {
                bool lightState = params["lgt_p"];
                digitalWrite(LED_PIN, lightState ? HIGH : LOW);
                Serial.printf("灯光已%s\n", lightState ? "开启" : "关闭");
            }
        }
    }
}

// 修改后的reportStatus函数
void reportStatus() {
    JsonDocument doc;
    doc["id"] = postMsgID++;
    doc["version"] = "1.0";
    
    JsonObject params = doc["params"].to<JsonObject>();
    params["f_btn"] = fanState;
    params["lgt_p"] = digitalRead(LED_PIN) == HIGH;

    String payload;
    serializeJson(doc, payload);
    
    String pubTopic = String("$sys/") + dht11Config.product_id + "/" + dht11Config.device_id + "/thing/property/post";
    client.publish(pubTopic.c_str(), payload.c_str());
    
    Serial.println("上报状态: " + payload);
}










// 网络连接函数
void WiFi_Connect() {
    WiFi.setAutoReconnect(true);
    WiFi.persistent(true);
    
    if(WiFi.status() == WL_CONNECTED) return;
    
    Serial.print("连接WiFi...");
    WiFi.begin(ssid, password);
    
    int attempts = 0;
    while (WiFi.status() != WL_CONNECTED && attempts++ < 20) {
        digitalWrite(LED, !digitalRead(LED));
        Serial.print(".");
        delay(500);
    }
    
    if(WiFi.status() == WL_CONNECTED) {
        Serial.printf("\n连接成功! IP: %s\n", WiFi.localIP().toString());
        digitalWrite(LED, HIGH);
    } else {
        Serial.println("\n连接失败!");
    }
}

bool OneNet_Connect() {
    if(client.connected()) return true;

    client.setServer(mqtt_server, 6002); 
    client.setCallback(mqttCallback);

    client.setServer(mqtt_server, mqtt_port);
    client.setKeepAlive(MQTT_KEEPALIVE);
    
    Serial.print("连接OneNET...");
    if(client.connect(dht11Config.device_id, dht11Config.product_id, dht11Config.token)) {
        Serial.println("成功!");
        
        // 订阅控制主题
        char setTopic[100];
        snprintf(setTopic, sizeof(setTopic), "$sys/%s/%s/thing/property/set", 
                dht11Config.product_id, dht11Config.device_id);
        client.subscribe(setTopic);
        
        // 订阅服务调用主题
        char serviceTopic[100];
        snprintf(serviceTopic, sizeof(serviceTopic), "$sys/%s/%s/thing/service/#", 
                dht11Config.product_id, dht11Config.device_id);
        client.subscribe(serviceTopic);
        
        return true;
    }
    Serial.println("失败! 错误码: " + String(client.state()));
    return false;
}




void checkConnection() {
    static uint32_t lastCheck = 0;
    if (millis() - lastCheck > 30000) {
        if (WiFi.status() != WL_CONNECTED) {
            WiFi_Connect();
        }
        if (!client.connected()) {
            if (millis() - lastReconnectAttempt > 5000) {
                lastReconnectAttempt = millis();
                if (OneNet_Connect()) {
                    lastReconnectAttempt = 0;
                }
            }
        }
        lastCheck = millis();
    }
    client.loop();
}





void OneNet_Prop_Post() {
    if(!client.connected()) {
        Serial.println("上报失败: MQTT未连接");
        return;
    }
    
    char payload[512];
    snprintf(payload, sizeof(payload), ONENET_TOPIC_PROP_FORMAT,
            postMsgID++, 
            dht11.getHumidity(),
            dht11.getTemperature(),
            mq2.getConcentration(),
            humanDetected ? "true" : "false",
            fanState ? "true" : "false",
            light.getLightState() ? "true" : "false");
    

     Serial.printf("[终端显示] 上报数据: %s\n", payload);
    // 上报到OneNET
    char topic[100];
    snprintf(topic, sizeof(topic), "$sys/%s/%s/thing/property/post", 
             dht11Config.product_id, dht11Config.device_id);
    
    if(client.publish(topic, payload)) {
        Serial.println("数据上报OneNET成功");
        digitalWrite(LED, !digitalRead(LED));
    } else {
        Serial.println("上报失败! 错误码: " + String(client.state()));
    }
    
   
}




